// cf http://sansmicrosoft.canalblog.com/archives/2011/05/18/21166859.html

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <search.h>

#define LGLIGNE 1000 //lg max de chaque chaine de caracteres

 

int main() {
  ENTRY e;
  ENTRY *retval;
  struct hsearch_data htable1 = (struct hsearch_data){0};
  struct hsearch_data htable2 = (struct hsearch_data){0};
  int retour=0;
  FILE *fp;
  char fichier[100];
  clock_t tick1,tick2; 
  char* str_ptr;
  char mot[LGLIGNE],motcle[LGLIGNE],donneesurmot[LGLIGNE];
  unsigned int nbajout,ajout_table;
  
  /////////////////////////////////////////////////////////
  // charge le premier dico => premiere table
  /////////////////////////////////////////////////////////
  printf("\nChaques enregistrement du fichier doivent se terminer par un newline\n");
  printf("Entrez le nom du 1er fichier:");
  scanf("%100s",fichier);
  ajout_table=0;
  if ((fp=fopen(fichier,"r")) == NULL) {printf("\nErreur lecture fichier\n"); exit(-1);}
  tick1=clock();
  while (fgets(mot,LGLIGNE,fp) != NULL)  {
    if ((str_ptr=strchr(mot,'\n'))!=NULL) *str_ptr='\0'; //supprime le LF
    if ((str_ptr=strchr(mot,'\r'))!=NULL) *str_ptr='\0'; //supprime le CR
    ajout_table++;
  }
  tick2=clock();
  fclose(fp);
  printf("Nb de ligne:%u\n",ajout_table);
  printf("nombre de ticks horloge:%7ld\n",tick2-tick1);
  ////////////////////////////////////////////////////////
  printf("\nEntrez le nombre d'ajout (0:max):");
  scanf("%u",&nbajout);
  if (nbajout == 0) nbajout=ajout_table;
  ////////////////////////////////////////////////////////
  hcreate_r((nbajout*1.5),&htable1); //50% plus large pour limiter les collisions
  ajout_table=0;
  fp=fopen(fichier,"r");
  tick1=clock();
  while (fgets(mot,LGLIGNE,fp) != NULL)  {
    if ((str_ptr=strchr(mot,'\n'))!=NULL) *str_ptr='\0'; //supprime le LF
    if ((str_ptr=strchr(mot,'\r'))!=NULL) *str_ptr='\0'; //supprime le CR
      //prépare le mot clé
      strcpy(motcle,"/");
      strcat(motcle,mot);
      strcat(motcle,"/");
      //prepare donneesurmot
      sprintf(donneesurmot,"%i:%s:9",(int)strlen(mot),mot);
      //
      e.key = strdup(motcle);  //la cle
      e.data = strdup(donneesurmot);  //ici la donnée est simplement le mot en clé
      retour = hsearch_r(e, ENTER, &retval, &htable1); //ajoute la donnée
      //
      if (retour == 0) { //si la table est pleine
        fprintf(stderr, "Erreur - l'entrée a échoué.\n");
        exit(1);
      }
      ajout_table++;
      if (ajout_table >= nbajout) {printf("\nNombre d'ajout atteint\n"); break;}
  }
  tick2=clock();
  fclose(fp);
  
  printf("Nombre de ticks horloge:%7ld\n",tick2-tick1);
  
  /////////////////////////////////////////////////////////
  // charge le deuxieme dico => deuxieme table
  /////////////////////////////////////////////////////////
  printf("\nEntrez le nom du 2ieme fichier:");
  scanf("%100s",fichier);
  ajout_table=0;
  if ((fp=fopen(fichier,"r")) == NULL) {printf("\nErreur lecture fichier\n"); exit(-1);}
  tick1=clock();
  while (fgets(mot,LGLIGNE,fp) != NULL)  {
    if ((str_ptr=strchr(mot,'\n'))!=NULL) *str_ptr='\0'; //supprime le LF
    if ((str_ptr=strchr(mot,'\r'))!=NULL) *str_ptr='\0'; //supprime le CR
    ajout_table++;
  }
  tick2=clock();
  fclose(fp);
  printf("Nb de ligne:%u\n",ajout_table);
  printf("nombre de ticks horloge:%7ld\n",tick2-tick1);
  ////////////////////////////////////////////////////////
  printf("\nEntrez le nombre d'ajout (0:max):");
  scanf("%u",&nbajout);
  if (nbajout == 0) nbajout=ajout_table;
  ////////////////////////////////////////////////////////
  hcreate_r((nbajout*1.5),&htable2); //50% plus large pour limiter les collisions
  ajout_table=0;
  fp=fopen(fichier,"r");
  tick1=clock();
  while (fgets(mot,LGLIGNE,fp) != NULL)  {
    if ((str_ptr=strchr(mot,'\n'))!=NULL) *str_ptr='\0'; //supprime le LF
    if ((str_ptr=strchr(mot,'\r'))!=NULL) *str_ptr='\0'; //supprime le CR
      //prépare le mot clé
      strcpy(motcle,"/");
      strcat(motcle,mot);
      strcat(motcle,"/");
      //prepare donneesurmot
      sprintf(donneesurmot,"%i:%s:9",(int)strlen(mot),mot);
      //
      e.key = strdup(motcle);  //la clé
      e.data = strdup(donneesurmot);  //ici c'est la donnée associée à la clé
      retour = hsearch_r(e, ENTER, &retval, &htable2); //ajoute une entrée
      //
      if (retour == 0) { //si la table est pleine
        fprintf(stderr, "Erreur - l'entrée a échoué! - La table est probablement pleine.\n");
        exit(1);
      }
      ajout_table++;
      if (ajout_table >= nbajout) {printf("\nNombre d'ajout atteint\n"); break;}
  }
  tick2=clock();
  fclose(fp);
  
  printf("Nombre de ticks horloge:%7ld\n",tick2-tick1);
  
  
//////////////////////////////////////////////////////
//Cherche dans les deux tables
/////////////////////////////////////////////////////
  
  *mot='\0';
  while (strcmp(mot,"quit!") != 0) {
      printf("Mot à chercher (quit! pour quitter):");
      scanf("%s",mot);
      //prepare le mot à chercher
      strcpy(motcle,"/");
      strcat(motcle,mot);
      strcat(motcle,"/");
      //le mot clé a chercher est assignée à e.key
      e.key = motcle;
      //dans le premier dico
      tick1=clock();
      //trouve l'entrée, retval point sur le resultat
      retour = hsearch_r(e, FIND, &retval, &htable1);
      tick2=clock();
      printf("\nNombre de ticks horloge:%7ld\n",tick2-tick1);
      if (retour) {
          printf("Résultat 1er dico, Clé:%s Donnée:%s\n",
                 retval->key,
                 (char*)retval->data);
      }
      else
        printf("Pas trouvé dans le premier dico!\n");
      //dans le deuxieme dico
      tick1=clock();
      //trouve l'entrée, retval point sur le resultat
      retour = hsearch_r(e, FIND, &retval, &htable2);
      tick2=clock();
      printf("Nombre de ticks horloge:%7ld\n",tick2-tick1);
      if (retour) {
          printf("Résultat 2ieme dico, Clé:%s Donnée:%s\n",
                 retval->key,
                 (char*)retval->data);
      }
      else
        printf("Pas trouvé dans le deuxieme dico!\n");
        
        
  }
  hdestroy_r(&htable1); //détruit la table et libére la mémoire
  hdestroy_r(&htable2); //détruit la table et libére la mémoire
  return 0;
}
//hcreate ne permet pas d'accroitre la dimension de la table et
//permet une seule table.
//hcreate_r, hsearch_r sont réentrant. Ils autorisent plusieurs 
//tables de hachages.
//JP Redonnet - 18 mai 2011

